﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Mail;
using System.Text;
using System.Threading.Tasks;
using VehicleRental.API.Models;
using VehicleRental.WpfClient.Models;
using VehicleRental.WpfClient.ViewModels;

namespace VehicleRental.WpfClient.Data
{
    public class DataPersister
    {
        private const int TokenLength = 50;
        private const string TokenChars = "qwertyuiopasdfghjklmnbvcxzQWERTYUIOPLKJHGFDSAZXCVBNM";
        private const int MinUsernameLength = 6;
        private const int MaxUsernameLength = 30;
        private const int AuthenticationCodeLength = 40;
        private const string ValidUsernameChars = "qwertyuiopasdfghjklzxcvbnmQWERTYUIOPLKJHGFDSAZXCVBNM1234567890_.@";

        protected static string AccessToken { get; set; }

        private const string BaseServicesUrl = "http://vehiclerental.apphb.com/api/";

        internal static void RegisterUser(string username, string email, string authenticationCode)
        {
            ValidateUsername(username);
            ValidateAuthCode(authenticationCode);
            ValidateEmail(email);
            var userModel = new UserModel()
            {
                Username = username,
                Email = email,
                AuthCode = authenticationCode
            };
            HttpRequester.Post(BaseServicesUrl + "users/register",
                userModel);
        }

        internal static string LoginUser(string username, string authenticationCode)
        {
            ValidateUsername(username);
            ValidateAuthCode(authenticationCode);
            var userModel = new UserModel()
            {
                Username = username,
                AuthCode = authenticationCode
            };
            var loginResponse = HttpRequester.Post<UserLoggedModel>(BaseServicesUrl + "auth/token",
                userModel);
            AccessToken = loginResponse.AccessToken.ToString();
            return loginResponse.Username;
        }

        internal static bool LogoutUser()
        {
            var headers = new Dictionary<string, string>();
            headers["X-accessToken"] = AccessToken;
            var isLogoutSuccessful = HttpRequester.Put(BaseServicesUrl + "users/logout", headers);
            return isLogoutSuccessful;
        }

        //internal static void CreateNewTodosList(string title, IEnumerable<TodoViewModel> todos)
        //{
        //    var listModel = new TodolistModel()
        //    {
        //        Title = title,
        //        Todos = todos.Select(t => new TodoModel()
        //        {
        //            Text = t.Text
        //        })
        //    };

        //    var headers = new Dictionary<string, string>();
        //    headers["X-accessToken"] = AccessToken;

        //    var response =
        //        HttpRequester.Post<ListCreatedModel>(BaseServicesUrl + "lists", listModel, headers);
        //}

        //internal static IEnumerable<TodoListViewModel> GetTodoLists()
        //{
        //    var headers = new Dictionary<string, string>();
        //    headers["X-accessToken"] = AccessToken;

        //    var todoListsModels =
        //        HttpRequester.Get<IEnumerable<TodolistModel>>(BaseServicesUrl + "lists", headers);
        //    return todoListsModels.
        //        AsQueryable().
        //         Select(model => new TodoListViewModel()
        //          {
        //              Id = model.Id,
        //              Title = model.Title,
        //              Todos = model.Todos.AsQueryable().Select(todo => new TodoViewModel()
        //              {
        //                  Id = todo.Id,
        //                  Text = todo.Text,
        //                  IsDone = todo.IsDone
        //              })
        //          });
        //}

        //internal static void ChangeState(int todoId)
        //{
        //    var headers = new Dictionary<string, string>();
        //    headers["X-accessToken"] = AccessToken;

        //    HttpRequester.Put(BaseServicesUrl + "todos/" + todoId, headers);
        //}

        private static void ValidateEmail(string email)
        {
            try
            {
                new MailAddress(email);
            }
            catch (FormatException ex)
            {
                throw new FormatException("Email is invalid", ex);
            }
        }

        //private void ValidateUser(UserModel userModel)
        //{
        //    if (userModel == null)
        //    {
        //        throw new FormatException("Username and/or password are invalid");
        //    }
        //    this.ValidateUsername(userModel.Username);
        //    this.ValidateAuthCode(userModel.AuthCode);
        //}

        private static void ValidateAuthCode(string authCode)
        {
            if (string.IsNullOrEmpty(authCode) || authCode.Length != AuthenticationCodeLength)
            {
                throw new FormatException("Password is invalid");
            }
        }

        private static void ValidateUsername(string username)
        {
            if (username.Length < MinUsernameLength || MaxUsernameLength < username.Length)
            {
                throw new FormatException(
                    string.Format("Username must be between {0} and {1} characters",
                        MinUsernameLength,
                        MaxUsernameLength));
            }
            if (username.Any(ch => !ValidUsernameChars.Contains(ch)))
            {
                throw new FormatException("Username contains invalid characters");
            }
        }

        public static IEnumerable<PlacesViewModel> GetAll()
        {
            var allPlaceModels = HttpRequester.Get<IEnumerable<PlaceModel>>(BaseServicesUrl + "/places/all");

            var allPlaces =
                from placeModel in allPlaceModels
                select new PlacesViewModel()
                {
                    Address = placeModel.Address,
                    Title = placeModel.Title,
                    Description = placeModel.Description,
                    ImageSource = placeModel.ImageSource,
                    Latitude = placeModel.Latitude,
                    Longitude = placeModel.Longitude,
                    VehiclesEnum = from vehicleModel in placeModel.Vehicles
                               select new VehicleViewModel()
                               {
                                   Manufacturer = vehicleModel.Manufacturer,
                                   Model = vehicleModel.Model,
                                   Type = vehicleModel.Type,
                                   Year = vehicleModel.Year,
                                   ImageSource = vehicleModel.ImageSource
    
                               }
                };

            return allPlaces;
        }

        public static IEnumerable<PrivatePlacesViewModel> GetAllPrivate()
        {
            var allPlaceModels = HttpRequester.Get<IEnumerable<PlaceModel>>(BaseServicesUrl + "/places/all");

            var allPlaces =
                from placeModel in allPlaceModels
                select new PrivatePlacesViewModel()
                {
                    Address = placeModel.Address,
                    Title = placeModel.Title,
                    Description = placeModel.Description,
                    ImageSource = placeModel.ImageSource,
                    Latitude = placeModel.Latitude,
                    Longitude = placeModel.Longitude,
                    VehiclesEnum = from vehicleModel in placeModel.Vehicles
                                   select new PrivateVehicleViewModel()
                                   {
                                       Manufacturer = vehicleModel.Manufacturer,
                                       Model = vehicleModel.Model,
                                       Type = vehicleModel.Type,
                                       Year = vehicleModel.Year,
                                       ImageSource = vehicleModel.ImageSource,
                                       PricePerHours = vehicleModel.PricePerHour,
                                       Fee = vehicleModel.VehicleFee,
                                       Id = vehicleModel.Id,
                                       PlaceId = vehicleModel.PlaceId,
                                       IsRented = vehicleModel.IsRented
                                   }
                };

            return allPlaces;
        }

   
        public static void RentCar(RentCarModel input)
        {
            var headers = new Dictionary<string, string>();
            headers["X-accessToken"] = AccessToken;
            var req = HttpRequester.PutWithData(BaseServicesUrl + "vehicles/rent/", headers, input);
        }
    }
}